home *** CD-ROM | disk | FTP | other *** search
/ Hot Super Models / Hot Super Models.iso / unix / x11 / xv200.tar / xv-2.00 / xvimage.c < prev    next >
C/C++ Source or Header  |  1992-01-02  |  23KB  |  911 lines

  1. /*
  2.  * xvimage.c - image manipulation functions (crop,resize,rotate...) for XV
  3.  *
  4.  *  Author:    John Bradley, University of Pennsylvania
  5.  *                (bradley@cis.upenn.edu)
  6.  *
  7.  *  Contains:
  8.  *            void Resize(int, int)
  9.  *            void DoCrop()
  10.  *     static void DoCrop1(int, int, int, int)
  11.  *            void UnCrop()
  12.  *            void AutoCrop()
  13.  *            void Rotate(int)
  14.  *     static void RotatePic(byte *, int *, int *, int)
  15.  *     static void FloydDitherize8(byte *)
  16.  *     static void FloydDitherize1(XImage *)
  17.  *            void FSDither(byte *, int, int, byte *)
  18.  *            void CreateXImage()
  19.  *            
  20.  */
  21.  
  22. /*
  23.  * Copyright 1989, 1990, 1991, 1992 by John Bradley and
  24.  *                       The University of Pennsylvania
  25.  *
  26.  * Permission to use, copy, and distribute for non-commercial purposes,
  27.  * is hereby granted without fee, providing that the above copyright
  28.  * notice appear in all copies and that both the copyright notice and this
  29.  * permission notice appear in supporting documentation. 
  30.  *
  31.  * The software may be modified for your own purposes, but modified versions
  32.  * may not be distributed.
  33.  *
  34.  * This software is provided "as is" without any express or implied warranty.
  35.  *
  36.  * The author may be contacted via:
  37.  *    US Mail:   John Bradley
  38.  *               GRASP Lab, Room 301C
  39.  *               3401 Walnut St.  
  40.  *               Philadelphia, PA  19104
  41.  *
  42.  *    Phone:     (215) 898-8813
  43.  *    EMail:     bradley@cis.upenn.edu       
  44.  */
  45.  
  46.  
  47. #include "xv.h"
  48.  
  49. #ifdef __STDC__
  50. static void DoCrop1(int, int, int, int);
  51. static void RotatePic(byte *, int *, int *, int);
  52. static void FloydDitherize8(byte *);
  53. static void FloydDitherize1(XImage *);
  54. #else
  55. static void DoCrop1(), RotatePic(), FloydDitherize8();
  56. static void FloydDitherize1();
  57. #endif
  58.  
  59.  
  60.  
  61. /***********************************/
  62. void Resize(w,h)
  63. int w,h;
  64. {
  65.   int          cy,ex,ey,*cxarr, *cxarrp;
  66.   byte        *clptr,*elptr,*epptr;
  67.   static char *rstr = "Resizing Image.  Please wait...";
  68.  
  69.   clptr = NULL;  cxarrp = NULL;  cy = 0;  /* shut up compiler */
  70.  
  71.   RANGE(w,1,maxWIDE);  RANGE(h,1,maxHIGH);
  72.  
  73.   SetISTR(ISTR_EXPAND, "%.3g x %.3g  (%d x %d)",
  74.       ((float) w) / cWIDE, ((float) h) / cHIGH, w, h);
  75.  
  76.   /* if same size, and Ximage created, do nothing */
  77.   if (w==eWIDE && h==eHIGH && theImage!=NULL) return;
  78.  
  79.   if (DEBUG) fprintf(stderr,"%s: Resize(%d,%d)  eSIZE=%d,%d  cSIZE=%d,%d\n",
  80.              cmd,w,h,eWIDE,eHIGH,cWIDE,cHIGH);
  81.  
  82.   BTSetActive(&but[BCROP],0);
  83.   SetCropString(but[BCROP].active);
  84.  
  85.   epicmode = EM_RAW;   SetEpicMode();
  86.  
  87.   if (w==cWIDE && h==cHIGH) {  /* 1:1 expansion.  point epic at cpic */
  88.     if (epic != cpic && epic!=NULL) free(epic);
  89.     epic = cpic;  eWIDE = cWIDE;  eHIGH = cHIGH;
  90.     if (psUp) PSResize();   /* if PSDialog is open, mention size change  */
  91.   }
  92.  
  93.   else {  /* have to actually SCALE THE PIC.  Drats! */
  94.     WaitCursor();
  95.  
  96.     /* if it's a big image, this could take a while.  mention it,
  97.         but only if we're actually changing the size, and only if we're
  98.     not using the root window */
  99.  
  100.     if (w*h>(500*500) && (w!=eWIDE || h!=eHIGH) && !useroot && mainW) {
  101.       XSetForeground(theDisp, theGC, fg);
  102.       XSetBackground(theDisp, theGC, bg);
  103.       XClearWindow(theDisp,mainW);
  104.       XFlush(theDisp);
  105.       XDrawImageString(theDisp,mainW,theGC,CENTERX(mfinfo,w/2,rstr),
  106.                CENTERY(mfinfo,h/2),rstr, strlen(rstr));
  107.       XFlush(theDisp);
  108.     }
  109.  
  110.     /* first, kill the old epic, if one exists */
  111.     if (epic!=NULL && epic!=cpic) {
  112.       free(epic);  epic = NULL;
  113.     }
  114.  
  115.     /* create a new epic of the appropriate size */
  116.     eWIDE = w;  eHIGH = h;
  117.     epic = (byte *) malloc(w*h);
  118.     if (epic==NULL) {
  119.       sprintf(str,"unable to malloc a %dx%d image\n",w,h);
  120.       FatalError(str);
  121.     }
  122.     if (psUp) PSResize();   /* if PSDialog is open, mention size change  */
  123.  
  124.     /* the scaling routine.  not really all that scary after all... */
  125.  
  126.     /* OPTIMIZATON IDEA.  Malloc an eWIDE array of ints which will hold the
  127.        values of the equation px = (pWIDE * ex) / eWIDE.  Faster than doing 
  128.        a mul and a div for every point in picture */
  129.  
  130.     cxarr = (int *) malloc(eWIDE * sizeof(int));
  131.     if (!cxarr) FatalError("unable to allocate cxarr");
  132.     for (ex=0; ex<eWIDE; ex++) 
  133.       cxarr[ex] = (cWIDE * ex) / eWIDE;
  134.  
  135.     elptr = epptr = epic;
  136.  
  137.     for (ey=0;  ey<eHIGH;  ey++, elptr+=eWIDE) {
  138.       if ((ey&127) == 0) WaitCursor();
  139.       cy = (cHIGH * ey) / eHIGH;
  140.       epptr = elptr;
  141.       clptr = cpic + (cy * cWIDE);
  142.       for (ex=0, cxarrp = cxarr;  ex<eWIDE;  ex++, epptr++) 
  143.     *epptr = clptr[*cxarrp++];
  144.     }
  145.     free(cxarr);
  146.   }
  147.  
  148.   /* now make something displayable out of epic */
  149.   CreateXImage();
  150. }
  151.                 
  152.  
  153.  
  154. /***********************************/
  155. void DoCrop()
  156. {
  157.   int i, x, y, x2, y2, w, h;
  158.  
  159.   if (!but[BCROP].active) return;
  160.  
  161.   /* turn off the cropping rectangle */
  162.   InvCropRect();  BTSetActive(&but[BCROP],0);
  163.  
  164.   /* sort crx1,crx2,cry1,cry2 so that crx1,cry1 are top left corner */
  165.   if (crx1>crx2) { i = crx1; crx1 = crx2; crx2 = i; }
  166.   if (cry1>cry2) { i = cry1; cry1 = cry2; cry2 = i; }
  167.  
  168.   /* see if cropping to same size, in which case do nothing */
  169.   if (crx2-crx1 == eWIDE && cry2-cry1 == eHIGH) return;
  170.  
  171.   /* figure out what the crop rectangles coordinates are in pic coordinates */
  172.   x = cXOFF + (crx1 * cWIDE) / eWIDE;
  173.   y = cYOFF + (cry1 * cHIGH) / eHIGH;
  174.   x2 = cXOFF + (crx2 * cWIDE) / eWIDE;
  175.   y2 = cYOFF + (cry2 * cHIGH) / eHIGH;
  176.   w = (x2 - x) + 1;
  177.   h = (y2 - y) + 1;
  178.  
  179.   if (w<1) w = 1;
  180.   if (x+w > pWIDE) w = pWIDE - x;
  181.   if (h<1) h = 1;
  182.   if (y+h > pHIGH) h = pHIGH - y;
  183.  
  184.   DoCrop1(x,y,w,h);
  185. }
  186.  
  187.  
  188. static void DoCrop1(x,y,w,h)
  189. int x,y,w,h;
  190. {
  191.   int   i,j;
  192.   byte *cp, *pp;
  193.   double expw, exph;
  194.  
  195.   epicmode = EM_RAW;   SetEpicMode();
  196.  
  197.   /* dispose of old cpic and epic */
  198.   if (epic && epic != cpic) free(epic);
  199.   if (cpic && cpic !=  pic) free(cpic);
  200.   epic = cpic = NULL;
  201.  
  202.   expw = (double) eWIDE / (double) cWIDE;
  203.   exph = (double) eHIGH / (double) cHIGH;
  204.  
  205.   crx1 = (int) ((x - cXOFF) * expw);
  206.   cry1 = (int) ((y - cYOFF) * exph);
  207.  
  208.   cXOFF = x;  cYOFF = y;  cWIDE = w;  cHIGH = h;
  209.   if (DEBUG) fprintf(stderr,"%s: cropping to %dx%d rectangle at %d,%d\n",
  210.              cmd, cWIDE, cHIGH, cXOFF, cYOFF);
  211.  
  212.   /* kill old Ximage so that Resize will be forced to generate a new one */
  213.   if (theImage != NULL) XDestroyImage(theImage);
  214.   theImage = NULL;
  215.  
  216.   /* at this point, we want to generate cpic, which will contain a
  217.      cWIDE*cHIGH subsection of 'pic', top-left at cXOFF,cYOFF */
  218.  
  219.   cpic = (byte *) malloc(cWIDE * cHIGH);
  220.   if (cpic == NULL) {
  221.     fprintf(stderr,"%s: unable to allocate memory for cropped image\n", cmd);
  222.     WUnCrop();
  223.     cpic = pic;  cXOFF = cYOFF = 0;  cWIDE = pWIDE;  cHIGH = pHIGH;
  224.     SetCropString(but[BCROP].active);
  225.     return;
  226.   }
  227.  
  228.   /* copy relevant pixels from pic to cpic */
  229.   cp = cpic;
  230.   for (i=0; i<cHIGH; i++) {
  231.     pp = pic + (i+cYOFF) * pWIDE + cXOFF;
  232.     for (j=0; j<cWIDE; j++) 
  233.       *cp++ = *pp++;
  234.   }
  235.  
  236.   SetCropString(but[BCROP].active);
  237.   BTSetActive(&but[BUNCROP],1);
  238.  
  239.   /* shrink window */
  240.   WCrop((int) (cWIDE * expw), (int) (cHIGH * exph));
  241. }
  242.  
  243.  
  244.  
  245. /***********************************/
  246. void UnCrop()
  247. {
  248.   int w,h;
  249.  
  250.   if (cpic == pic) return;     /* not cropped */
  251.  
  252.   BTSetActive(&but[BUNCROP],0);
  253.   epicmode = EM_RAW;   SetEpicMode();
  254.  
  255.   /* dispose of old cpic and epic */
  256.   if (epic && epic != cpic) free(epic);
  257.   if (cpic && cpic !=  pic) free(cpic);
  258.   epic = cpic = NULL;
  259.   
  260.   /* kill old Ximage so that Resize will be forced to generate a new one */
  261.   if (theImage != NULL) XDestroyImage(theImage);
  262.   theImage = NULL;
  263.  
  264.   w = (pWIDE * eWIDE) / cWIDE;
  265.   h = (pHIGH * eHIGH) / cHIGH;
  266.   RANGE(w,1,maxWIDE);  RANGE(h,1,maxHIGH);
  267.  
  268.   WUnCrop();
  269.   cpic = pic;  cXOFF = cYOFF = 0;  cWIDE = pWIDE;  cHIGH = pHIGH;
  270.   SetCropString(but[BCROP].active);
  271. }
  272.   
  273.  
  274. /***********************************/
  275. void AutoCrop()
  276. {
  277.   byte *cp, *cp1;
  278.   int  i, ctop, cbot, cleft, cright;
  279.   byte bgcol;
  280.  
  281.   ctop = cbot = cleft = cright = 0;
  282.  
  283.   /* crop the top */
  284.   cp = cpic;
  285.   bgcol = cp[0];
  286.  
  287.   while (ctop+1 < cHIGH) {
  288.     /* see if we can delete this line */
  289.     for (i=0, cp1=cp; i<cWIDE && *cp1==bgcol; i++, cp1++);
  290.     if (i==cWIDE) { cp += cWIDE;  ctop++; }
  291.     else break;
  292.   }
  293.  
  294.  
  295.   /* crop the bottom */
  296.   cp = cpic + (cHIGH-1) * cWIDE;
  297.   bgcol = cp[0];
  298.  
  299.   while (ctop + cbot + 1 < cHIGH) {
  300.     /* see if we can delete this line */
  301.     for (i=0, cp1=cp; i<cWIDE && *cp1==bgcol; i++,cp1++);
  302.     if (i==cWIDE) { cp -= cWIDE;  cbot++; }
  303.     else break;
  304.   }
  305.  
  306.  
  307.   /* crop the left side */
  308.   cp = cpic;
  309.   bgcol = cp[0];
  310.  
  311.   while (cleft + 1 < cWIDE) {
  312.     /* see if we can delete this line */
  313.     for (i=0, cp1=cp; i<cHIGH && *cp1==bgcol; i++, cp1 += cWIDE);
  314.     if (i==cHIGH) { cp++; cleft++; }
  315.     else break;
  316.   }
  317.  
  318.  
  319.   /* crop the right side */
  320.   cp = cpic + cWIDE-1;
  321.   bgcol = cp[0];
  322.  
  323.   while (cleft + cright + 1 < cWIDE) {
  324.     /* see if we can delete this line */
  325.     for (i=0, cp1=cp; i<cHIGH && *cp1==bgcol; i++, cp1 += cWIDE);
  326.     if (i==cHIGH) { cp--; cright++; }
  327.     else break;
  328.   }
  329.  
  330.  
  331.   /* do the actual cropping */
  332.   if (cleft || ctop || cbot || cright)
  333.     DoCrop1(cXOFF+cleft, cYOFF+ctop, cWIDE-(cleft+cright), cHIGH-(ctop+cbot));
  334. }
  335.  
  336.  
  337. /***********************************/
  338. void Rotate(dir)
  339. int dir;
  340. {
  341.   int i;
  342.  
  343.   /* dir=0: clockwise, else counter-clockwise */
  344.   WaitCursor();
  345.  
  346.   RotatePic(pic, &pWIDE, &pHIGH, dir);
  347.  
  348.   /* rotate clipped version and modify 'clip' coords */
  349.   if (cpic != pic && cpic != NULL) {
  350.     if (!dir) {
  351.       i = pWIDE - (cYOFF + cHIGH);      /* have to rotate offsets */
  352.       cYOFF = cXOFF;
  353.       cXOFF = i;
  354.     }
  355.     else {
  356.       i = pHIGH - (cXOFF + cWIDE);
  357.       cXOFF = cYOFF;
  358.       cYOFF = i;
  359.     }
  360.     WaitCursor();
  361.     RotatePic(cpic, &cWIDE, &cHIGH,dir);
  362.   }
  363.   else { cWIDE = pWIDE;  cHIGH = pHIGH; }
  364.  
  365.   /* rotate expanded version */
  366.   if (epic != cpic && epic != NULL) {
  367.     WaitCursor();
  368.     RotatePic(epic, &eWIDE, &eHIGH,dir);
  369.   }
  370.   else { eWIDE = cWIDE;  eHIGH = cHIGH; }
  371.  
  372.   CreateXImage();
  373.   WRotate();
  374. }
  375.  
  376.  
  377. /************************/
  378. static void RotatePic(pic, wp, hp, dir)
  379. byte *pic;
  380. int *wp, *hp;
  381. int dir;
  382. {
  383.   /* rotates a w*h array of bytes 90 deg clockwise (dir=0) 
  384.      or counter-clockwise (dir != 0).  swaps w and h */
  385.  
  386.   byte *pic1, *pix1, *pix;
  387.   int          i,j;
  388.   unsigned int w,h;
  389.  
  390.   w = *wp;  h = *hp;  
  391.   pix1 = pic1 = (byte *) malloc(w*h);
  392.   if (!pic1) FatalError("Not enough memory to rotate!");
  393.  
  394.   /* do the rotation */
  395.   if (dir==0) {
  396.     for (i=0; i<w; i++)        /* CW */
  397.       for (j=h-1, pix=pic+(h-1)*w + i; j>=0; j--, pix1++, pix-=w) 
  398.     *pix1 = *pix;
  399.   }
  400.   else {
  401.     for (i=w-1; i>=0; i--)     /* CCW */
  402.       for (j=0, pix=pic+i; j<h; j++, pix1++, pix+=w) 
  403.     *pix1 = *pix;
  404.   }
  405.  
  406.  
  407.   /* copy the rotated buffer into the original buffer */
  408.   memcpy(pic, pic1, w*h);
  409.  
  410.   free(pic1);
  411.  
  412.   /* swap w and h */
  413.   *wp = h;  *hp = w;
  414. }
  415.  
  416.   
  417.  
  418. /***********************************/
  419. void Flip(dir)
  420. int dir;
  421. {
  422.   /* dir=0: flip horizontally, else vertically */
  423.   WaitCursor();
  424.  
  425.   FlipPic(pic, pWIDE, pHIGH, dir);
  426.  
  427.   /* flip clipped version */
  428.   if (cpic != pic && cpic != NULL) {
  429.     WaitCursor();
  430.     FlipPic(cpic, cWIDE, cHIGH, dir);
  431.   }
  432.  
  433.   /* flip expanded version */
  434.   if (epic != cpic && epic != NULL) {
  435.     WaitCursor();
  436.     FlipPic(epic, eWIDE, eHIGH,dir);
  437.   }
  438.  
  439.   CreateXImage();
  440.   if (mainW && !useroot) DrawWindow(0, 0, eWIDE, eHIGH);
  441. }
  442.  
  443.  
  444. /************************/
  445. void FlipPic(pic, w, h, dir)
  446. byte *pic;
  447. int w, h;
  448. int dir;
  449. {
  450.   /* flips a w*h array of bytes horizontally (dir=0) or vertically (dir!=0) */
  451.  
  452.   byte *plin;
  453.   int   i,j,k;
  454.  
  455.   if (dir==0) {                /* horizontal flip */
  456.     for (i=0; i<h; i++) {
  457.       plin = pic + i*w;
  458.       for (j=0; j<w/2; j++) {
  459.     k = plin[j];  
  460.     plin[j] = plin[w - 1 - j];
  461.     plin[w - 1 - j] = k;
  462.       }
  463.     }
  464.   }
  465.  
  466.   else {                      /* vertical flip */
  467.     for (i=0; i<w; i++)
  468.       for (j=0; j<h/2; j++) {
  469.     k = pic[j*w + i];
  470.     pic[j*w + i] = pic[(h - 1 - j)*w + i];
  471.     pic[(h - 1 -j)*w + i] = k;
  472.       }
  473.   }
  474. }
  475.  
  476.   
  477.  
  478. /************************/
  479. static void FloydDitherize8(image)
  480.      byte *image;
  481. {
  482.   /* takes epic, and builds a black&white dithered version of it.
  483.      stores result in 8bit Pixmap format in 'image' */
  484.  
  485.   int i;
  486.   byte *p;
  487.  
  488.   FSDither(epic, eWIDE, eHIGH, image);
  489.  
  490.   /* set to 'black' and 'white' instead of '0' and '1' */
  491.   if (black != 0 || white != 1) {
  492.     for (i=eWIDE*eHIGH, p=image; i>0; i--, p++) {
  493.       if (*p) *p = white;  else *p = black;
  494.     }
  495.   }
  496. }
  497.  
  498.  
  499.  
  500. /************************/
  501. static void FloydDitherize1(ximage)
  502.      XImage *ximage;
  503. {
  504.   /* same as FloydDitherize8, but output is a 1-bit per pixel XYBitmap,
  505.      packed 8 pixels per byte */
  506.  
  507.   register short *dp;
  508.   register byte   pix8, bit;
  509.   short          *dithpic;
  510.   int             i, j, err, bperln, order;
  511.   byte           *pp, *image, w1, b1, w8, b8, rgb[256];
  512.  
  513.  
  514.   /* first thing to do is build rgb[], which will hold the B/W intensity
  515.      of the colors in the r,g,b arrays */
  516.   for (i=0; i<256; i++)
  517.     rgb[i] = MONO(r[i], g[i], b[i]);
  518.  
  519.   image  = (byte *) ximage->data;
  520.   bperln = ximage->bytes_per_line;
  521.   order  = ximage->bitmap_bit_order;
  522.  
  523.   if (DEBUG) fprintf(stderr,"Ditherizing1...");
  524.  
  525.   dithpic = (short *) malloc(eWIDE * eHIGH * sizeof(short));
  526.   if (dithpic == NULL) FatalError("not enough memory to ditherize");
  527.  
  528.   w1 = white&0x1;  b1=black&0x1;
  529.   w8 = w1<<7;  b8 = b1<<7;        /* b/w bit in high bit */
  530.   
  531.   /* copy rgb[epic] into dithpic so that we can run the algorithm */
  532.   pp = epic;  dp = dithpic;
  533.   for (i=eHIGH * eWIDE; i>0; i--) *dp++ = fsgamcr[rgb[*pp++]];
  534.  
  535.   dp = dithpic;
  536.   pp = image;
  537.  
  538.   for (i=0; i<eHIGH; i++) {
  539.     pp = image + i*bperln;
  540.  
  541.     if ((i&63) == 0) WaitCursor();
  542.  
  543.     if (order==LSBFirst) {
  544.       bit = pix8 = 0;
  545.       for (j=0; j<eWIDE; j++,dp++) {
  546.     if (*dp<128) { err = *dp;     pix8 |= b8; }
  547.             else { err = *dp-255; pix8 |= w8; }
  548.  
  549.     if (bit==7) {
  550.       *pp++ = pix8;  bit=pix8=0;
  551.     }
  552.     else { pix8 >>= 1;  bit++; }
  553.  
  554.     if (j<eWIDE-1) dp[1] += ((err*7)/16);
  555.  
  556.     if (i<eHIGH-1) {
  557.       dp[eWIDE] += ((err*5)/16);
  558.       if (j>0)       dp[eWIDE-1] += ((err*3)/16);
  559.       if (j<eWIDE-1) dp[eWIDE+1] += (err/16);
  560.     }
  561.       }
  562.       if (bit) *pp++ = pix8>>(7-bit);  /* write partial byte at end of line */
  563.     }
  564.  
  565.     else {   /* order==MSBFirst */
  566.       bit = pix8 = 0;
  567.       for (j=0; j<eWIDE; j++,dp++) {
  568.     if (*dp<128) { err = *dp;     pix8 |= b1; }
  569.             else { err = *dp-255; pix8 |= w1; }
  570.  
  571.     if (bit==7) {
  572.       *pp++ = pix8;  bit=pix8=0;
  573.     }
  574.     else { pix8 <<= 1; bit++; }
  575.  
  576.     if (j<eWIDE-1) dp[1] += ((err*7)/16);
  577.  
  578.     if (i<eHIGH-1) {
  579.       dp[eWIDE] += ((err*5)/16);
  580.       if (j>0)       dp[eWIDE-1] += ((err*3)/16);
  581.       if (j<eWIDE-1) dp[eWIDE+1] += (err/16);
  582.     }
  583.       }
  584.       if (bit) *pp++ = pix8<<(7-bit);  /* write partial byte at end of line */
  585.     }
  586.   }
  587.  
  588.   if (DEBUG) fprintf(stderr,"done\n");
  589.  
  590.   free(dithpic);
  591. }
  592.  
  593.  
  594.  
  595. /************************/
  596. void FSDither(inpic, w, h, outpic)
  597. byte *inpic, *outpic;
  598. int   w,h;
  599. {
  600.   /* takes inpic, and builds a black&white dithered version of it.
  601.      stores result as 1 byte per pixel format in 'image'
  602.      black = 0;  white = 1;
  603.      temporarily mallocs a w*h array of SHORTS.
  604.      (need to be signed, also to avoid overflow problems.)  */
  605.  
  606.   /* floyd-steinberg dithering.
  607.    *
  608.    * ----   x    7/16
  609.    * 3/16  5/16  1/16
  610.    *
  611.    */
  612.  
  613.   short *dp, *dithpic;
  614.   int    i, j, err, w1, h1;
  615.   byte  *pp, rgb[256];
  616.  
  617.   if (DEBUG) fprintf(stderr,"Ditherizing...");
  618.  
  619.   /* first thing to do is build rgb[], which will hold the B/W intensity
  620.      of the colors in the r,g,b arrays */
  621.   for (i=0; i<256; i++)
  622.     rgb[i] = MONO(r[i], g[i], b[i]);
  623.  
  624.  
  625.   dithpic = (short *) malloc(w*h * sizeof(short));
  626.   if (dithpic == NULL) FatalError("not enough memory to ditherize");
  627.  
  628.   w1 = w-1;  h1 = h-1;
  629.  
  630.   /* copy rgb[inpic] into dithpic so that we can run the algorithm */
  631.   pp = inpic;  dp = dithpic;
  632.   for (i=w*h; i>0; i--) *dp++ = fsgamcr[rgb[*pp++]];
  633.  
  634.   dp = dithpic;  pp = outpic;
  635.   for (i=0; i<h; i++) {
  636.     if ((i&15) == 0) WaitCursor();
  637.     for (j=0; j<w; j++,dp++,pp++) {
  638.       if (*dp<128) { err = *dp;     *pp = 0; }
  639.               else { err = *dp-255; *pp = 1; }
  640.  
  641.       if (j<w1) dp[1] += ((err*7)/16);
  642.  
  643.       if (i<h1) {
  644.         dp[w] += ((err*5)/16);
  645.         if (j>0)  dp[w1] += ((err*3)/16);
  646.         if (j<w1) dp[w+1] += (err/16);
  647.       }
  648.     }
  649.   }
  650.  
  651.   if (DEBUG) fprintf(stderr,"done\n");
  652.  
  653.   free(dithpic);
  654. }
  655.  
  656.  
  657.  
  658.  
  659.  
  660.  
  661. /***********************************/
  662. void CreateXImage()
  663. {
  664.   int    i;
  665.  
  666.  
  667.   /*
  668.    * this has to do the tricky bit of converting the data in 'epic'
  669.    * into something usable for X.
  670.    *
  671.    * Algorithm notes:
  672.    *   if dispDEEP is 8, nothing has to be done other than create an
  673.    *      Ximage (ZPixmap, depth=8) and point it at the 'epic' data.
  674.    *
  675.    *   if dispDEEP is 1, format'll be an XYBitmap, special case code
  676.    *   
  677.    *   if dispDEEP is 4, format'll be a ZPixmap, 4 or 8 bits per pixel
  678.    *
  679.    *   if dispDEEP is 6, format'll be a ZPixmap, 8 bits per pixel
  680.    *
  681.    *   if dispDEEP is 16, format'll be a ZPixmap, 16 bits per pixel
  682.    *
  683.    *   if dispDEEP is 24 or 32, format'll be a ZPixmap.  32 bits per pixel
  684.    *
  685.    */
  686.  
  687.   if (DEBUG) 
  688.     fprintf(stderr,"%s: creating a %dx%d Ximage, %d bits deep\n",
  689.         cmd, eWIDE, eHIGH, dispDEEP);
  690.  
  691.   /* destroy old image and imagedata, if there is one */
  692.   if (theImage) XDestroyImage(theImage);
  693.   theImage = NULL;
  694.  
  695.   if (!epic) {
  696.     /* fprintf(stderr,"CreateXImage called while epic was null\n"); */
  697.     Resize(eWIDE,eHIGH);
  698.     return;
  699.   }
  700.  
  701.   switch (dispDEEP) 
  702.     {
  703.  
  704.     case 8:
  705.       {
  706.       byte  *imagedata, *ip, *pp;
  707.  
  708.       imagedata = (byte *) malloc(eWIDE*eHIGH);
  709.       if (!imagedata) FatalError("couldn't malloc imagedata");
  710.       
  711.       if (ncols==0) FloydDitherize8(imagedata);
  712.       else {
  713.     for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++,ip++) {
  714.       if ((i&0x1ffff) == 0) WaitCursor();
  715.       *ip = (byte) cols[*pp];
  716.     }
  717.       }
  718.  
  719.       theImage = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0,
  720.                   (char *) imagedata, eWIDE, eHIGH, 8, 0);
  721.       if (!theImage) FatalError("couldn't create theImage!");
  722.       }
  723.       break;
  724.  
  725.     /*********************************/
  726.  
  727.     case 1:
  728.       {
  729.       byte  *imagedata;
  730.  
  731.       theImage = XCreateImage(theDisp, theVisual, dispDEEP, XYPixmap, 0, NULL, 
  732.                   eWIDE, eHIGH, 8, 0);
  733.       if (!theImage) FatalError("couldn't create theImage!");
  734.       imagedata = (byte *) malloc(theImage->bytes_per_line * eHIGH);
  735.       if (!imagedata) FatalError("couldn't malloc imagedata");
  736.       theImage->data = (char *) imagedata;
  737.       FloydDitherize1(theImage);
  738.       }
  739.       break;
  740.       
  741.     /*********************************/
  742.       
  743.     case 4: {
  744.       byte  *imagedata, *ip, *pp;
  745.       byte *lip;
  746.       int  bperline, half, j;
  747.  
  748.       theImage = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL, 
  749.                   eWIDE, eHIGH, 8, 0);
  750.       if (!theImage) FatalError("couldn't create theImage!");
  751.  
  752.       bperline = theImage->bytes_per_line;
  753.       imagedata = (byte *) malloc(bperline * eHIGH);
  754.       if (!imagedata) FatalError("couldn't malloc imagedata");
  755.       theImage->data = (char *) imagedata;
  756.  
  757.       if (ncols==0) {            /* ditherize */
  758.     byte *dith;
  759.     dith = (byte *) malloc(eWIDE * eHIGH);
  760.     if (!dith) FatalError("can't create dithered image");
  761.     FloydDitherize8(dith);
  762.  
  763.     if (theImage->bits_per_pixel == 4) {
  764.       for (i=0, pp=dith, lip=imagedata; i<eHIGH; i++, lip+=bperline)
  765.         for (j=0, ip=lip, half=0; j<eWIDE; j++,pp++,half++) {
  766.           if (theImage->bitmap_bit_order == LSBFirst) {
  767.         if (half&1) { *ip = *ip + ((*pp&0x0f)<<4);  ip++; }
  768.         else *ip = *pp&0x0f;
  769.           }
  770.           else {
  771.         if (half&1) { *ip = *ip + (*pp&0x0f);  ip++; }
  772.         else *ip = (*pp&0x0f) << 4;
  773.           }
  774.         }
  775.     }
  776.     else if (theImage->bits_per_pixel == 8)
  777.       memcpy(imagedata, dith, eWIDE*eHIGH);
  778.     
  779.     else FatalError("This display is too bizarre.  Can't create XImage.");
  780.  
  781.     free(dith);
  782.       }
  783.  
  784.       else {     /* don't ditherize */
  785.     if (theImage->bits_per_pixel == 4) {
  786.       for (i=0, pp=epic, lip=imagedata; i<eHIGH; i++, lip+=bperline) {
  787.         if ((i&127) == 0) WaitCursor();
  788.         for (j=0, ip=lip, half=0; j<eWIDE; j++,pp++,half++) {
  789.           if (theImage->bitmap_bit_order == LSBFirst) {
  790.         if (half&1) { *ip = *ip + ((cols[*pp]&0x0f)<<4);  ip++; }
  791.         else *ip = cols[*pp]&0x0f;
  792.           }
  793.           else {
  794.         if (half&1) { *ip = *ip + (cols[*pp]&0x0f);  ip++; }
  795.         else *ip = (cols[*pp]&0x0f) << 4;
  796.           }
  797.         }
  798.       }
  799.     }
  800.     else if (theImage->bits_per_pixel == 8) {
  801.       for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++,ip++) {
  802.         if ((i&0x1ffff) == 0) WaitCursor();
  803.         *ip = (byte) cols[*pp];
  804.       }
  805.     }
  806.     else FatalError("This display's too bizarre.  Can't create XImage.");
  807.       }
  808.       
  809.       }
  810.       break;
  811.       
  812.     /*********************************/
  813.       
  814.     case 6: {
  815.       byte  *imagedata, *ip, *pp;
  816.       int  bperline;
  817.  
  818.       theImage = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL, 
  819.                   eWIDE, eHIGH, 8, 0);
  820.       if (!theImage) FatalError("couldn't create theImage!");
  821.  
  822.       if (theImage->bits_per_pixel != 8)
  823.     FatalError("This display's too bizarre.  Can't create XImage.");
  824.  
  825.       bperline = theImage->bytes_per_line;
  826.       imagedata = (byte *) malloc(bperline * eHIGH);
  827.       if (!imagedata) FatalError("couldn't malloc imagedata");
  828.       theImage->data = (char *) imagedata;
  829.  
  830.       if (ncols==0) FloydDitherize8(imagedata);
  831.       else {
  832.     for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++,ip++) {
  833.       if ((i&0x1ffff) == 0) WaitCursor();
  834.       *ip = (byte) cols[*pp];
  835.     }
  836.       }
  837.     }
  838.     break;
  839.       
  840.     /*********************************/
  841.  
  842.     case 16: {
  843.       short  *imagedata, *ip;
  844.       byte  *pp;
  845.       imagedata = (short *) malloc(2*eWIDE*eHIGH);
  846.       if (!imagedata) FatalError("couldn't malloc imagedata");
  847.  
  848.       theImage = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0,
  849.                   (char *) imagedata, eWIDE, eHIGH, 16, 0);
  850.       if (!theImage) FatalError("couldn't create theImage!");
  851.  
  852.       if (theImage->byte_order == MSBFirst)
  853.     for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++) {
  854.       if ((i&0x1ffff) == 0) WaitCursor();
  855.       *ip++ = cols[*pp] & 0xffff;
  856.     }
  857.       else
  858.     for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++) {
  859.       if ((i&0x1ffff) == 0) WaitCursor();
  860.       *ip++ = ((cols[*pp] >> 8) & 0xff) | ((cols[*pp] & 0xff) >> 8);
  861.     }
  862.     }
  863.     break;
  864.  
  865.       
  866.     /*********************************/
  867.  
  868.     case 24:
  869.     case 32:
  870.       {
  871.       byte  *imagedata, *ip, *pp;
  872.       imagedata = (byte *) malloc(4*eWIDE*eHIGH);
  873.       if (!imagedata) FatalError("couldn't malloc imagedata");
  874.       
  875.       theImage = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0,
  876.                   (char *) imagedata, eWIDE, eHIGH, 32, 0);
  877.       if (!theImage) FatalError("couldn't create theImage!");
  878.       
  879.       if (theImage->byte_order == MSBFirst) 
  880.     for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++) {
  881.       if ((i&0x1ffff) == 0) WaitCursor();
  882.       *ip++ = 0;
  883.       *ip++ = (cols[*pp]>>16) & 0xff;
  884.       *ip++ = (cols[*pp]>>8) & 0xff;
  885.       *ip++ =  cols[*pp] & 0xff;
  886.     }
  887.       else 
  888.     for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++) {
  889.       if ((i&0x1ffff) == 0) WaitCursor();
  890.       *ip++ =  cols[*pp] & 0xff;
  891.       *ip++ = (cols[*pp]>>8) & 0xff;
  892.       *ip++ = (cols[*pp]>>16) & 0xff;
  893.       *ip++ = 0;
  894.     }
  895.       }      
  896.       break;
  897.  
  898.     /*********************************/
  899.  
  900.     default: 
  901.       sprintf(str,"no code to handle this display type (%d bits deep)",
  902.           dispDEEP);
  903.       FatalError(str);
  904.       break;
  905.     }
  906. }
  907.  
  908.  
  909.  
  910.  
  911.